#pragma warning(disable:4786)       //Long identifiers using set<>.

#include <windows.h>
#include <set>
#include "lib.h"
#include "BonusBingoCard.h"

BonusBingoCard::BonusBingoCard()
{
	m_id = 0;
	ZeroMemory( m_values, sizeof( m_values[0][0] ) * NUM_BINGO_PICKS );
}

BonusBingoCard::~BonusBingoCard()
{
    //Sanity check that we left the "wild" position alone
    ASSERT( 0 == m_values[2][2] ); 
}

int32 BonusBingoCard::getID() const
{
	return m_id;
}

void BonusBingoCard::setID( int32 m_id )
{
	this->m_id = m_id;
}

bool8 BonusBingoCard::isActive() const
{
    return m_active;
}

void BonusBingoCard::activate(bool8 activated)
{
    m_active = activated;
}

void BonusBingoCard::setValues( const uint8* firstValue )
{
    memcpy( m_values, firstValue, 
            sizeof( m_values[0][0] ) * ( NUM_BINGO_PICKS ) );

    //leave the wild slot open
    m_values[2][2] = 0;
}

uint8 BonusBingoCard::getValue( const uint8 column, const uint8 row ) const
{
    ASSERT( row < 5 );
    ASSERT( column < 5 );
    
    return m_values[row][column];
}

int32 BonusBingoCard::GetColumn( uint8 value )
{
    int32 column = BonusBingoCard::NUM_COLUMNS;

    if ( 1 <= value && value <= 15 )
    {
        column = BonusBingoCard::COLUMN_B;
    }
    else if ( 16 <= value &&  value <= 30 )
    {
        column = BonusBingoCard::COLUMN_I;
    }
    else if ( (31 <= value && value <= 45) || value == NUM_WILD_VALUE)
    {
        column = BonusBingoCard::COLUMN_N;
    }
    else if ( 46 <= value && value <= 60 )
    {
        column = BonusBingoCard::COLUMN_G;
    }
    else if ( 61 <= value && value <= 75 )
    {
        column = BonusBingoCard::COLUMN_O;
    }

    return column;
}

bool8 BonusBingoCard::isValid() const
{
    using namespace std;

    typedef set<uint8> uint8set;

    const uint8* pValues = &m_values[0][0];
    const uint8* pEnd = pValues + NUM_BINGO_PICKS;

    uint8set temp( pValues, pEnd );

    //No duplicates - any duplicates will result in a smaller set.
    if ( temp.size() != NUM_BINGO_PICKS )
    {
        return false;
    }

    //all m_values must fall between 0 && MAX_VALUE
    //Since the set is sorted, we only need to look at begin() and rbegin()
    if ( *(temp.begin()) < 0 || *(temp.rbegin()) > NUM_MAX_VALUE )
        return false;

    //And there can only be five in a column (including the 0 in the 'N'-2 spot)
    int32 cardsInColumn[NUM_COLUMNS];
    ZeroMemory( cardsInColumn, sizeof( cardsInColumn) );

    for( uint8set::iterator current = temp.begin(), end = temp.end();
         current != end;
         ++current )
    {
        ++cardsInColumn[ GetColumn( *current ) ];
    }
    
    for ( int columnIndex(COLUMN_B) ; columnIndex < NUM_COLUMNS ; ++columnIndex )
    {
        if ( cardsInColumn[columnIndex] != 5 )
        {
            //Hey - there are only 5 rows in each column
            return false;
        }
    }

    return true;
}